defmodule EliPhxPlay.Context.Groups do
  @moduledoc """
  群聊模块
  负责处理群聊相关的逻辑
  """
  import Ecto.Query, warn: false
  alias EliPhxPlay.Repo
  alias EliPhxPlay.ChatSchema.{Groups, GroupMembers, Users}
  alias Phoenix.PubSub

  @doc """
  创建群聊
  """
def create_group(attrs) do
  # 强制使用系统生成的群号，忽略用户提供的群号
  attrs_with_code = Map.put(attrs, :group_code, generate_unique_group_code())

  Repo.transaction(fn ->
    # 1. 创建群聊（带系统生成的群号）
    case %Groups{}
        |> Groups.changeset(attrs_with_code)
        |> Repo.insert() do
      {:ok, group} ->
        # 2. 自动将创建者添加为群主
        member_attrs = %{
          group_id: group.group_id,
          user_id: attrs[:owner_id] || attrs["owner_id"],
          role: "owner",
          status: "active"
        }

        case %GroupMembers{}
            |> GroupMembers.changeset(member_attrs)
            |> Repo.insert() do
          {:ok, _member} ->
            group  # 返回群聊信息
          {:error, changeset} ->
            Repo.rollback(changeset)
        end

      {:error, %Ecto.Changeset{errors: [group_code: {"群号已被使用", _}]}} ->
        # 群号冲突，回滚事务并重试
        Repo.rollback(:group_code_conflict)

      {:error, changeset} ->
        Repo.rollback(changeset)
    end
  end)
  |> case do
    {:error, :group_code_conflict} ->
      # 群号冲突时重试
      retry_create_group(attrs, 2)
    result ->
      result
  end
end


defp retry_create_group(attrs, attempts) when attempts > 0 do
  # 重新生成群号（系统生成，不使用用户提供的）
  attrs_with_new_code = Map.put(attrs, :group_code, generate_unique_group_code())

  Repo.transaction(fn ->
    # 创建群聊
    case %Groups{}
        |> Groups.changeset(attrs_with_new_code)
        |> Repo.insert() do
      {:ok, group} ->
        # 自动将创建者添加为群主
        member_attrs = %{
          group_id: group.group_id,
          user_id: attrs[:owner_id] || attrs["owner_id"],
          role: "owner",
          status: "active"
        }

        case %GroupMembers{}
            |> GroupMembers.changeset(member_attrs)
            |> Repo.insert() do
          {:ok, _member} ->
            group
          {:error, changeset} ->
            Repo.rollback(changeset)
        end

      {:error, %Ecto.Changeset{errors: [group_code: {"群号已被使用", _}]}} ->
        Repo.rollback(:group_code_conflict)

      {:error, changeset} ->
        Repo.rollback(changeset)
    end
  end)
  |> case do
    {:error, :group_code_conflict} ->
      :timer.sleep(Enum.random(1..10))  # 短暂延迟避免竞争
      retry_create_group(attrs, attempts - 1)
    result ->
      result
  end
end

defp retry_create_group(_attrs, 0) do
  {:error, "群号生成失败，请重试"}
end


defp retry_create_group(attrs, attempts) when attempts > 0 do
  # 重新生成群号（系统生成，不使用用户提供的）
  attrs_with_new_code = Map.put(attrs, :group_code, generate_unique_group_code())

  Repo.transaction(fn ->
    # 创建群聊
    case %Groups{}
        |> Groups.changeset(attrs_with_new_code)
        |> Repo.insert() do
      {:ok, group} ->
        # 自动将创建者添加为群主
        member_attrs = %{
          group_id: group.group_id,
          user_id: attrs[:owner_id] || attrs["owner_id"],
          role: "owner",
          status: "active"
        }

        case %GroupMembers{}
            |> GroupMembers.changeset(member_attrs)
            |> Repo.insert() do
          {:ok, _member} ->
            group
          {:error, changeset} ->
            Repo.rollback(changeset)
        end

      {:error, %Ecto.Changeset{errors: [group_code: {"群号已被使用", _}]}} ->
        Repo.rollback(:group_code_conflict)

      {:error, changeset} ->
        Repo.rollback(changeset)
    end
  end)
  |> case do
    {:error, :group_code_conflict} ->
      :timer.sleep(Enum.random(1..10))  # 短暂延迟避免竞争
      retry_create_group(attrs, attempts - 1)
    result ->
      result
  end
end

defp retry_create_group(_attrs, 0) do
  {:error, "群号生成失败，请重试"}
end

@doc """
生成唯一群号
"""
def generate_unique_group_code do
  max_query = from g in Groups,
              select: coalesce(max(g.group_code), "10000000")

  current_max = Repo.one(max_query)
  (String.to_integer(current_max) + 1) |> Integer.to_string()
end

@doc """
检查群号是否可用
"""
def group_code_available?(group_code) do
  count = Groups
          |> where([g], g.group_code == ^group_code)
          |> Repo.aggregate(:count, :group_id)

  count == 0
end

@doc """
根据群号查找群组
"""
def get_group_by_code(group_code) do
  Groups
  |> where([g], g.group_code == ^group_code)
  |> Repo.one()
end

@doc """
获取群组的显示信息，包含群号
"""
def get_group_display_info(%Groups{} = group) do
  %{
    group_id: group.group_id,
    group_code: group.group_code,
    group_name: group.group_name,
    group_description: group.group_description,
    avatar_url: Groups.avatar_url(group)
  }
end

@doc """
根据群号或群名模糊查询群组
返回最多5个匹配的群组
"""
def search_groups(search_term, limit \\ 5) do
  search_term = String.trim(search_term)

  case search_term do
    "" -> []
    term when byte_size(term) < 2 -> []  # 搜索词太短
    term ->
      # 构建模糊查询
      like_pattern = "%#{term}%"

      Groups
      |> where([g],
          ilike(g.group_name, ^like_pattern) or
          ilike(g.group_code, ^like_pattern)
        )
      |> order_by([g], [
          # 精确匹配群号优先
          fragment("CASE WHEN ? = ? THEN 0 ELSE 1 END", g.group_code, ^term),
          # 群名开头匹配优先
          fragment("CASE WHEN ? ILIKE ? THEN 0 ELSE 1 END", g.group_name, ^"#{term}%"),
          # 按群号排序
          g.group_code
        ])
      |> limit(^limit)
      |> Repo.all()
  end
end


end
